package com.ytjj.quartz.task;

import com.alibaba.fastjson.JSON;
import com.gexin.fastjson.JSONObject;
import com.ytjj.common.api.CommonResult;
import com.ytjj.common.constants.QueueConstants;
import com.ytjj.common.dto.mqdto.OrderRecordDto;
import com.ytjj.common.utils.HttpClientUtil;
import com.ytjj.common.utils.feishu.FeiShuUtil;
import com.ytjj.qmyx.mall.mapper.*;
import com.ytjj.qmyx.mall.model.*;
import com.ytjj.quartz.config.SupplyApiConfig;
import com.ytjj.quartz.constants.IsPayConstant;
import com.ytjj.quartz.model.ReissueLogisticsVO;
import com.ytjj.quartz.service.OrdersService;
import com.ytjj.quartz.service.YxOrdersSendRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 订单定时任务
 *
 *
 * @version 1.0
 *
 */
@Component
@Slf4j
public class OrdersTask {

    @Autowired
    private OrdersService ordersService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Resource
    private YxOrdersSendRecordService yxOrdersSendRecordService;
    @Resource
    private OrdersInfoMapper ordersInfoMapper;
    @Resource
    private ProductMapper productMapper;
    @Resource
    private GroupBuyUserRelMapper groupBuyUserRelMapper;
    @Resource
    private ReissueLogisticsMapper reissueLogisticsMapper;
    @Resource
    private OrdersPayMapper ordersPayMapper;

    @Value("${spring.profiles.active}")
    private String profiles;

    @Resource
    private SupplyApiConfig supplyApiConfig;
    Executor pools = new ThreadPoolExecutor(5, 10, 5,
            TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024 * 1024));



    private Date getBeforeDate(int min) {
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault());
        ldt = ldt.plusMinutes(min);
        Date beforeDate = Date.from(ldt.atZone( ZoneId.systemDefault()).toInstant());
        return beforeDate;
    }

    /**
     * 定时刷新微信支付状态
     */
    @Scheduled(cron = "0 0/2 * * * ?")
    public void updateWxAppOrdersStatus() {
        log.debug("===== 开始定时刷新微信app支付状态 =====");
        ordersService.updateWxAppOrdersStatus();
        log.debug("===== 结束定时刷新微信app支付状态 =====");
    }


    /**
     * 超时取消订单
     */
    @Scheduled(cron = "0 0/2 * * * ?")
    public void cancelOrder(){
        log.debug("===== 开始取消超1小时未支付的订单 =====");
        ordersService.cancelOrder();
        log.debug("===== 结束取消超1小时未支付的订单 =====");
    }


    /**
     * 超时取消订单
     */
    @Scheduled(cron = "0 0/2 * * * ?")
    public void updateErrorOrderReamrk(){
        log.debug("===== 开始修改了订单支付了,但是备注显示超时未支付,订单超时未支付,已取消 =====");
        ordersService.updateErrorOrderRemark();
        log.debug("===== 结束修改了订单支付了,但是备注显示超时未支付,订单超时未支付,已取消 =====");
    }


    /**
     * 定时推送订单到rabbitMQ（保存到MongoDB）
     */
    @Scheduled(cron = "0 0/5 * * * ? ")
    public void pushCreateOrderToRabbitMQ() {
        log.debug("===pushCreateOrderTo rabbitMQ is start===");
        Date beforeDate = getBeforeDate(-30);
        //30分钟以内创建的订单
        List<Orders> orders = ordersService.queryCurTimeBefore30MinCreateOrders(beforeDate, new Date());

        if (!CollectionUtils.isEmpty(orders)) {
            List<String> orderNoList = orders.stream().map(Orders::getOrderNo).collect(Collectors.toList());
            GroupBuyUserRelExample groupBuyUserRelExample = new GroupBuyUserRelExample();
            groupBuyUserRelExample.createCriteria().andOrderNoIn(orderNoList);
            List<GroupBuyUserRel> groupBuyUserRelList = groupBuyUserRelMapper.selectByExample(groupBuyUserRelExample);//属于拼团的订单
            List<String> groupOrderNoList = groupBuyUserRelList.stream().map(GroupBuyUserRel::getOrderNo).collect(Collectors.toList());

            List<Orders> filterOrderResults = new ArrayList<>();//过滤掉拼团订单后的结果集合
            orders.stream().forEach(order -> {
                if (!groupOrderNoList.contains(order.getOrderNo())) {
                    filterOrderResults.add(order);
                }
            });


            filterOrderResults.stream().forEach(order -> {
                List<OrdersInfo> ordersInfoList = ordersInfoMapper.selectOrderInfoByOrderId(order.getId());
                ordersInfoList.stream().forEach(orderInfo -> {
                    Product product = productMapper.selectByPrimaryKey(orderInfo.getProductId());
                    OrderRecordDto orderRecordDto = new OrderRecordDto(order.getUserId()==null?"0":String.valueOf(order.getUserId()),order.getId(), orderInfo.getId(), order.getOrderNo(), product.getId(), product.getProductName(),
                            product.getCostPrice(), product.getOriginalPrice(), product.getPrice(), "JSAPI".equals(order.getOrderSource()) ? "weapp" : order.getOrderSource(), order.getChannel(),
                            orderInfo.getActivityType(), IsPayConstant.NO.intValue(), StringUtils.isEmpty(order.getUserAddress()) ? 0 : 1, order.getCreateTime(), order.getIsFirstBuy(),
                            order.getUserId(),order.getPayType(),order.getPaySource(),order.getCity(),order.getArea(),order.getAddress(),order.getProvince(),
                            order.getUserAddress(),null,new Date(), order.getDynamicId());
                    int count = yxOrdersSendRecordService.queryByOrderInfoId(orderInfo.getId(), 1);
                    if(0==count){
                        OrdersSendRecord sendRecord = new OrdersSendRecord();
                        sendRecord.setOrderinfoId(orderInfo.getId());
                        sendRecord.setType((byte)1);
                        sendRecord.setSucFlag((byte)1);
                        sendRecord.setCreateTime(new Date());
                        try {
                            pools.execute(() -> {
                                rabbitTemplate.convertAndSend(QueueConstants.ORDER_RECORD_QUEUE,orderRecordDto);
                            });
                        } catch (Exception e) {
                            log.error("===订单创建发送rabbitmq异常==={},{}", e, order);
                            sendRecord.setSucFlag((byte)0);
                        }
                        yxOrdersSendRecordService.insert(sendRecord);
                    }
                });
            });
        }

        log.debug("===pushCreateOrderTo rabbitMQ is end===");

        log.debug("===pushIsPayOrderTo rabbitMQ is start===");
        orders = ordersService.queryCurTimeBefore30MinIsPayOrders(beforeDate, new Date());//30分钟以内已支付订单
        if (!CollectionUtils.isEmpty(orders)) {
            List<String> orderNoList = orders.stream().map(Orders::getOrderNo).collect(Collectors.toList());
            GroupBuyUserRelExample groupBuyUserRelExample = new GroupBuyUserRelExample();
            groupBuyUserRelExample.createCriteria().andOrderNoIn(orderNoList);
            List<GroupBuyUserRel> groupBuyUserRelList = groupBuyUserRelMapper.selectByExample(groupBuyUserRelExample);//属于拼团的订单
            List<String> groupOrderNoList = groupBuyUserRelList.stream().map(GroupBuyUserRel::getOrderNo).collect(Collectors.toList());

            List<Orders> filterOrderResults = new ArrayList<>();//过滤掉拼团订单后的结果集合
            orders.stream().forEach(order -> {
                if (!groupOrderNoList.contains(order.getOrderNo())) {
                    filterOrderResults.add(order);
                }
            });

            filterOrderResults.stream().forEach(order -> {
                    List<OrdersInfo> ordersInfoList = ordersInfoMapper.selectOrderInfoByOrderId(order.getId());
                    ordersInfoList.stream().forEach(orderInfo -> {
                        Product product = productMapper.selectByPrimaryKey(orderInfo.getProductId());
                        OrderRecordDto orderRecordDto = new OrderRecordDto(order.getUserId()==null?"0":String.valueOf(order.getUserId()),order.getId(),orderInfo.getId(), order.getOrderNo(), product.getId(), product.getProductName(),
                                product.getCostPrice(), product.getOriginalPrice(), product.getPrice(), "JSAPI".equals(order.getOrderSource()) ? "weapp" : order.getOrderSource(), order.getChannel(),
                                orderInfo.getActivityType(), IsPayConstant.YES.intValue(), StringUtils.isEmpty(order.getUserAddress()) ? 0 : 1, order.getCreateTime(), order.getIsFirstBuy(),
                                order.getUserId(),order.getPayType(),order.getPaySource(),order.getCity(),order.getArea(),order.getAddress(),order.getProvince(),
                                order.getUserAddress(),order.getPayTime(),new Date(), order.getDynamicId());
                        int count = yxOrdersSendRecordService.queryByOrderInfoId(orderInfo.getId(), 2);
                        if(0==count){
                            OrdersSendRecord sendRecord = new OrdersSendRecord();
                            sendRecord.setOrderinfoId(orderInfo.getId());
                            sendRecord.setType((byte)2);
                            sendRecord.setSucFlag((byte)1);
                            sendRecord.setCreateTime(new Date());
                            try {
                                pools.execute(() -> {
                                    rabbitTemplate.convertAndSend(QueueConstants.ORDER_RECORD_QUEUE, orderRecordDto);
                                });
                            } catch (Exception e) {
                                log.error("===订单支付发送rabbitmq异常==={},{}", e, order);
                                sendRecord.setSucFlag((byte)0);
                            }
                            yxOrdersSendRecordService.insert(sendRecord);
                        }
                    });
            });
        }
        log.debug("===pushIsPayOrderTo rabbitMQ is end===");
    }


    /**
     * 定时刷新支付宝支付状态
     */
//    @Scheduled(cron = "0 0/5 * * * ?")
    public void updateAliPayAppOrdersStatus() {
        log.debug("===== 开始定时刷新支付宝APP支付状态 =====");
        ordersService.updateAliPayAppOrdersStatus(null);
        log.debug("===== 结束定时刷新支付宝APP支付状态 =====");
    }


    /**
     * 更新补单状态
     * @param
     * @return void
     */

    @Scheduled(cron = "0 0 0/1 * * ?")
//    @Scheduled(cron = "0 0/2 * * * ?")
    public void queryLogisticsRecord() {
        //查询未完结的补单信息
        List<ReissueLogistics> list = reissueLogisticsMapper.selectByFinishStatus();
        if (list.size() > 50) {
            int moreVal = list.size() % 50;// 10
            int forNum = list.size() / 50;// 1
            if (moreVal > 0) {// 10 > 0
                forNum = forNum + 1;// 2
            }
            for (int i = 0; i < forNum; i++) {// 2
                List<ReissueLogistics> requestsNew = null;
                if (i == forNum - 1) { // 1 == 1
                    int toIndex = list.size(); // 60
                    requestsNew = list.subList(i * 50, toIndex); // 50 ~ 60
                }else {
                    requestsNew = list.subList(i * 50, i * 50 + 50); // 50
                }
                queryHandleBySupplyChain(requestsNew);
            }
        }else {
            if (!CollectionUtils.isEmpty(list)) {
                queryHandleBySupplyChain(list);
            }

        }
    }

    /**
     * 查询并更新供应链的补单状态
     * @param list
     * @return void
     */
    public void queryHandleBySupplyChain(List<ReissueLogistics> list) {
        List<Integer> orderInfoIdList = list.stream().map(ReissueLogistics::getOrderInfoId).collect(Collectors.toList());
        List<String> orderInfoIdToStringList = orderInfoIdList.stream().map(String::valueOf).collect(Collectors.toList());
        String orderInfoIds = String.join(",", orderInfoIdToStringList);
        Map map = new HashMap();
        map.put("orderInfoIds",orderInfoIds);
        map.put("shopId",supplyApiConfig.getShopId());
        String resultJson = HttpClientUtil.doGet(supplyApiConfig.getUrl() + "/order/queryLogisticsRecord", map, supplyApiConfig.getHeadsMap());
        log.debug("====queryLogisticsRecord"+resultJson+"====");
        CommonResult commonResult = JSONObject.parseObject(resultJson, CommonResult.class);
        if (200 == commonResult.getCode()) {
            List<ReissueLogisticsVO> inventoryDTOs = JSON.parseArray(commonResult.getData().toString(), ReissueLogisticsVO.class);
            if (!CollectionUtils.isEmpty(inventoryDTOs)) {
                inventoryDTOs.stream().forEach(item -> {
                    ReissueLogistics reissueLogistics = new ReissueLogistics();
                    reissueLogistics.setId(item.getReissueLogisticsId());
                    reissueLogistics.setStatus(item.getStatus());
                    reissueLogistics.setExpressCompanyNo(item.getExpressCompanyNo());
                    reissueLogistics.setExpressNo(item.getExpressNo());
                    reissueLogistics.setSupplementaryDay(item.getSupplementaryDay());
                    reissueLogistics.setFeedbackUrl(item.getFeedbackUrl());
                    reissueLogistics.setLogisticsReceiptTime(item.getLogisticsReceiptTime());
                    reissueLogistics.setExpressRecord(item.getExpressRecord());
                    reissueLogistics.setExpressText(item.getExpressText());
                    reissueLogistics.setRefuseReason(item.getRefuseReason());
                    reissueLogistics.setFinishStatus(item.getFinishStatus());
                    reissueLogistics.setFinishTime(item.getFinishTime());
                    reissueLogistics.setStatusCode(item.getStatusCode());
                    reissueLogistics.setStatusDesc(item.getStatusDesc());
                    reissueLogistics.setReissueStatus(item.getReissueStatus());
                    reissueLogistics.setRefuseTime(item.getRefuseTime());
                    reissueLogistics.setCheckTime(item.getCheckTime());
                    reissueLogistics.setDescr(item.getDescr());
                    reissueLogisticsMapper.updateReissueLogistics(reissueLogistics);
                });
            }
        }
    }
    /**
     * 检查供应链订单状态修改 （30天内，从2分钟10分钟一次,避开整点）
     * 包括发送发货短信
     */
    @Scheduled(cron = "0 2/10 * * * ?")
    public void checkSupplyChainOrder(){
        log.debug("===== 开始检查供应链订单状态修改 =====");
        ordersService.checkSupplyChainOrder(null);
        log.debug("===== 结束检查供应链订单状态修改 =====");
    }

    /**
     * 检查供应链订单状态修改 （30天前的订单更新，从4分开始，每2小时一次,避开整点）
     * 包括发送发货短信
     */
    @Scheduled(cron = "0 4 0/2 1/1 * ?")
    public void checkSupplyChainOrderTwo(){
        log.debug("===== 开始检查供应链订单状态修改 =====");
        ordersService.checkSupplyChainOrder(1);
        log.debug("===== 结束检查供应链订单状态修改 =====");
    }

    /**
     * 检查供应链售后订单状态修改(订单状态为6的)
     */
    @Scheduled(cron = "0 0/6 * * * ?")
    public void updateSupplyChainOrder(){
        log.debug("===== 开始检查供应链订单状态修改(订单状态为6的) =====");
        ordersService.updateSupplyChainOrder();
        log.debug("===== 结束检查供应链订单状态修改(订单状态为6的) =====");
    }



    /**
     * 推送订单到供应链
     * 每天下午2点推送
     */
    @Scheduled(cron = "0 0 14 * * ?")
    //每小时推送一次
//    @Scheduled(cron = "0 0 0/1 * * ?")
    public void uploadOrderEveryDay() {
        log.info("===每天推送一次订单到供应链开始===");
        try {
            ordersService.uploadOrderToSupply();
        } catch (Exception e) {
            log.error("定时任务推单出错,{}",e);
            FeiShuUtil.sendMsg(String.format("定时任务推单出错，{}",e.getMessage()));
        }
        log.info("===每天推送一次订单到供应链结束");
    }

    /**
     * 修复已付款但被关闭的订单
     */
    @Scheduled(cron = "0 0/5 * * * ?")
    public void repairPrepaidOrders(){
        List<Orders> orders = ordersPayMapper.selectOrdersByPaySuccess();
        for (Orders e : orders) {
            ordersService.dealOrdersByPaySuccess(e);
        }
    }



    /*********************************** 以下是注释了的定时任务 *************************************/

    /**
     * 定时查询今天通过测评购买的订单状态是否为已完成,已完成的赠送佣金
     */
//    @Scheduled(cron = "0 0/20 * * * ?")
//    public void giveBrokerageByDynamic(){
//        log.debug("===== 开始查询今天通过测评购买的订单状态是否为已完成 =====");
////        ordersService.giveBrokerageByDynamic();
//        log.debug("===== 结束查询今天通过测评购买的订单状态是否为已完成 =====");
//    }


    /**
     * 刷新过期订单状态 （重复的定时任务）
     */
//    @Scheduled(cron = "0 0/3 * * * ?")
    public void updateOrdersStatus() {
        log.debug("===== 开始刷新过期订单状态 =====");
        ordersService.updateOrdersStatus();
        log.debug("===== 结束刷新过期订单状态 =====");
    }



    /**
     * 推送过期订单消息
     */
//    @Scheduled(cron = "0 0/3 * * * ?")
//    public void OrdersStatus() {
//        log.debug("===== 开始推送过期订单消息 =====");
//        ordersService.ordersStatus();
//        log.debug("===== 结束推送过期订单消息 =====");
//    }

    /**
     * 定时每晚12更新状态为过期通知消息
     */
//    @Scheduled(cron = "59 59 23 * * ?")
//    public void MessageStatus() {
//        log.debug("===== 开始更新过期通知消息 =====");
//        ordersService.MessageStatus();
//        log.debug("===== 结束更新过期通知消息 =====");
//    }

    /**
     * 定时处理未在规定时间完成助力单信息
     */
//    @Scheduled(cron = "0 0/5 * * * ?")
//    public void HelpStatus() {
//        log.debug("===== 开始更新助力单信息 =====");
//        ordersService.HelpStatus();
//        log.debug("===== 结束更新助力单信息 =====");
//    }


    /**
     * 更新快递订单
     */
//    @Scheduled(cron = "0 0 0/2 * * ?")
//    @Async
//    public void updateExpressOrders(){
//        log.info("===== 开始定时刷新快递订单状态 =====");
//        if("pd".equals(profiles)){
//            ordersService.updateExpressOrders();
//        }
//        log.info("===== 结束定时刷新快递订单状态 =====");
//    }

    //    @Scheduled(cron = "0 0/5 * * * ?")
//    @Async
    public void sendMessageInMinutes() {
        log.info("=========== 开始定时检查5分钟内订单订单状态  ====");
        ordersService.sendMessageInMinutes();
        log.info("============= 结束定时检查5分钟内订单状态  ======");
    }

    /**
     * 更新异常订单状态 (作废)
     */
//    @Scheduled(cron = "0/2 * * * * ?")
//    public void examineOrdersExpressStatus(){
//        log.info("===== 开始定时检查订单快递状态 =====");
//        ordersService.examineOrdersExpressStatus();
//        log.info("===== 结束定时检查订单快递状态 =====");
//    }

    //    @Scheduled(cron = "0/2 * * * * ?") 作废
//    public void examineOrdersExpressStatus2(){
//        log.info("===== 开始定时检查订单快递状态 =====");
//        ordersService.examineOrdersExpressStatus2();
//        log.info("===== 结束定时检查订单快递状态 =====");
//    }

    /**
     * 每小时查询一次订单状态为已发货但没快递单号的订单数据,发货时间超12天就修改状态为已完成
     */
//    @Scheduled(cron = "0 0/15 * * * ? ")
    public void findOrderAllByStatus() {
        log.info("===== 开始定时检查订单快递发货状态 =====");
        ordersService.findOrderAllByStatus();
        log.info("===== 结束定时检查订单快递发货状态 =====");
    }
    /**
     * 检查一个小时之内的已支付的订单,在供应链中是否存在
     */
//    @Scheduled(cron = "0 0/5 * * * ?")
    public void checkIsPayOrder(){
        log.info("===== 开始检查一个小时之内的已支付的订单,在供应链中是否存在 =====");
        ordersService.checkIsPayOrder();
        log.info("===== 结束检查一个小时之内的已支付的订单,在供应链中是否存在 =====");
    }

    /**
     * 检查一天之内的已支付的订单,在供应链中是否存在
     */
//    @Scheduled(cron = "0 0 0/2 * * ?")
    public void checkIsPayOrderBy1Day(){
        log.info("===== 开始检查一天之内的已支付的订单,在供应链中是否存在 =====");
        ordersService.checkIsPayOrderBy1Day();
        log.info("===== 结束检查一天之内的已支付的订单,在供应链中是否存在 =====");
    }

    /**
     * 检查10分钟内是否产生支付订单
     */
    @Scheduled(cron = "0 0/10 7-12 * * ?")
    public void checkIsPayOrderCount(){
        log.info("===== 开始检查10分钟内是否产生支付订单 =====");
        ordersService.checkIsPayOrderCount(10);
        log.info("===== 结束检查10分钟内是否产生支付订单 =====");
    }

    /**
     * 检查30分钟内是否产生支付订单
     */
    @Scheduled(cron = "0 0/30 12-23 * * ?")
    public void checkIsPayOrderCountTwo(){
        log.info("===== 开始检查30分钟内是否产生支付订单 =====");
        ordersService.checkIsPayOrderCount(30);
        log.info("===== 结束检查30分钟内是否产生支付订单 =====");
    }

    /**
     * 检查60分钟内是否产生支付订单
     */
    @Scheduled(cron = "0 0 0-7 * * ?")
    public void checkIsPayOrderCountThree(){
        log.info("===== 开始检查10分钟内是否产生支付订单 =====");
        ordersService.checkIsPayOrderCount(60);
        log.info("===== 结束检查10分钟内是否产生支付订单 =====");
    }

    /**
     * 检查60分钟内支付订单的地址是都包含多个省或者多个市
     */
//    @Scheduled(cron = "0 0 * * * ?")
    public void checkOrdersAddress(){
        log.info("===== 开始检查60分钟内支付订单的地址是都包含多个省或者多个市的订单 =====");
        ordersService.checkOrdersAddress(60);
        log.info("===== 结束检查60分钟内支付订单的地址是都包含多个省或者多个市的订单 =====");
    }
}
